/****************************************************************************
 *
 **************************************************************************/

#include <stdio.h>
#include <string.h>
#include "nuc900_reg.h"
#include "wblib.h"
#include "usbd.h"
#include "nuc900_sic.h"

#define CACHE_ON
//#define USBD_SCATTER_GETHER

#define USE_EPA_B
//#define USE_EPC_D
//#define USE_EPE_F


#if 1
#define MSG_DEBUG(...)
#define MSG_WARNING(...)
#define MSG_ERROR(...)
#else
#define MSG_DEBUG			printf
#define MSG_WARNING			printf
#define MSG_ERROR			printf		
#endif

#define USE_TOKEN	0

/* The interface number of mass storage interface */
#define MASS_INF_NUM		1

/* The endpoint number of mass storage interface's endpoint */ 
#define EP_NUM_ISO			1
#define EP_NUM_BKO			2
#define EP_NUM_INT			3

/* length of descriptors */
#define DEVICE_DSCPT_LEN	0x12
#define CONFIG_DSCPT_LEN	0x20
#define STR0_DSCPT_LEN		0x04
#define STR1_DSCPT_LEN		0x10
#define STR2_DSCPT_LEN		0x10
#define STR3_DSCPT_LEN		20

#define QUALIFIER_DSCPT_LEN		0x0a
#define OSCONFIG_DSCPT_LEN		0x20

#define USBD_DMA_LEN	0x10000

/* for USB */
USB_CMD_T	_usb_cmd_pkt;
UINT32 volatile _usbd_remlen=0;
BOOL volatile _usbd_remlen_flag=0;
UINT16 *_usbd_ptr;

UINT8 volatile GET_DEV_Flag=0;
UINT8 volatile GET_CFG_Flag=0;
UINT8 volatile GET_QUL_Flag=0;
UINT8 volatile GET_OSCFG_Flag=0;
UINT8 volatile GET_STR_Flag=0;
UINT8 volatile CLASS_CMD_Flag=0;
UINT8 volatile usbdGetConfig=0;
UINT8 volatile usbdGetInterface=0;
UINT8 volatile usbdGetStatus=0;

// for DMA state flag
UINT8 volatile _usbd_DMA_Flag=0;
UINT8 volatile _usbd_Less_MPS=0;
UINT8 volatile _usbd_DMA_Dir;

UINT8 volatile bulkonlycmd=0;
UINT8 volatile USBModeFlag=0;    //way
UINT8 volatile ResetFlag=0;
UINT8 volatile _usbd_resume=0;

UINT32 volatile usbdMaxPacketSize;
// _usbd_devstate:	1.default state 2.addressed state 3.configured state
UINT32	_usbd_devstate;
UINT32	_usbd_address;
UINT32	_usbd_speedset;
UINT16	_usbd_confsel;
UINT16	_usbd_altsel;
UINT32	_usbd_haltep0=0;
UINT8	_usbd_haltep1=0;
UINT8	_usbd_haltep2=0;
UINT8 _usbd_unhaltep=0xff;

INT		remotewakeup=0;
INT		enableremotewakeup;
INT		enabletestmode;
INT		disableremotewakeup;
INT		testselector;
UINT32	usbdGetStatusData;

extern void USB_Initialize(void);
extern UINT8 Flash_Init(void);
void usbdTransferAddress(UINT32 uaddr, UINT32 len, UINT32 IsRead);

struct dma_descriptor {
	UINT32	uPhyAddress;
	UINT32	uCountAndDir;
} USBD_DMA_Desc[16];

__align(32) static UINT16 _DeviceDescriptor[9] =
{
	0x0112, 0x0200, 0x0000, 0x4000, 0x0416, 0x0910, 0x0100, 0x0201, 0x0101
};

__align(32) static UINT16 _QualifierDescriptor[6] = 
{
	0x060a, 0x0200, 0x0000, 0x4000, 0x0001, 0x0000
};

__align(32) static UINT16 _ConfigurationBlock[16] =
{
	0x0209, 0x0020, 0x0101, 0xC000, 0x0932, 0x0004, 0x0200, 0x0508, 0x0050, 0x0507,
	0x0281, 0x0200, 0x0701, 0x0205, 0x0002, 0x0102
};

__align(32) static UINT16 _ConfigurationBlockFull[16] =
{
	0x0209, 0x0020, 0x0101, 0xC000, 0x0932, 0x0004, 0x0200, 0x0508, 0x0050, 0x0507,
	0x0281, 0x0040, 0x0701, 0x0205, 0x4002, 0x0100
};

__align(32) static UINT16 _OSConfigurationBlock[16] =
{
	0x0709, 0x0020, 0x0101, 0xC000, 0x0932, 0x0004, 0x0200, 0x0508, 0x0050, 0x0507,
	0x0281, 0x0040, 0x0701, 0x0205, 0x4002, 0x0100
};

__align(32) static UINT16 _StringDescriptor0[2] = 
{
	0x0304, 0x0409
};

__align(32) static UINT16 _StringDescriptor1[8] = 
{
	0x0310, 0x0057, 0x0049, 0x004e, 0x0042, 0x004f, 0x004e, 0x0044
};

__align(32) static UINT16 _StringDescriptor2[8] = 
{
	0x0310, 0x0057, 0x0039, 0x0030, 0x0050, 0x0039, 0x0031, 0x0030
};

__align(32) static UINT16 _StringDescriptor3[10] = 
{
	0x0314, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039
};

void usbdClearAllFlags()
{
	CLASS_CMD_Flag=0;
	GET_DEV_Flag=0;
	GET_CFG_Flag=0;
	GET_QUL_Flag=0;
	GET_OSCFG_Flag=0;
	GET_STR_Flag=0;
	usbdGetConfig=0;
	usbdGetInterface=0;
	usbdGetStatus=0;
}

void UsbResetDma(void) // reset DMA and endpoints 
{
	outpw(REG_USBD_DMA_CNT, 0);
	outpw(REG_USBD_DMA_CTRL_STS, 0x80);
	outpw(REG_USBD_DMA_CTRL_STS, 0x00);

#ifdef USE_EPA_B
	outpw(REG_USBD_EPA_RSP_SC, 0);
	outpw(REG_USBD_EPB_RSP_SC, 0);
	outpw(REG_USBD_EPA_RSP_SC, EP_TOGGLE);
	outpw(REG_USBD_EPB_RSP_SC, EP_TOGGLE);
	outpw(REG_USBD_EPA_RSP_SC, 0x01);		// flush fifo
	outpw(REG_USBD_EPB_RSP_SC, 0x01);		// flush fifo
#endif
#ifdef USE_EPC_D
	outpw(REG_USBD_EPC_RSP_SC, 0);
	outpw(REG_USBD_EPD_RSP_SC, 0);
	outpw(REG_USBD_EPC_RSP_SC, EP_TOGGLE);
	outpw(REG_USBD_EPD_RSP_SC, EP_TOGGLE);
	outpw(REG_USBD_EPC_RSP_SC, 0x01);		// flush fifo
	outpw(REG_USBD_EPD_RSP_SC, 0x01);		// flush fifo
#endif
#ifdef USE_EPE_F
	outpw(REG_USBD_EPE_RSP_SC, 0);
	outpw(REG_USBD_EPF_RSP_SC, 0);
	outpw(REG_USBD_EPE_RSP_SC, EP_TOGGLE);
	outpw(REG_USBD_EPF_RSP_SC, EP_TOGGLE);
	outpw(REG_USBD_EPE_RSP_SC, 0x01);		// flush fifo
	outpw(REG_USBD_EPF_RSP_SC, 0x01);		// flush fifo
#endif
	
}

void usbd_update_device()
{
	//update this device for set requests
	switch(_usb_cmd_pkt.bRequest)
	{
		case USBR_SET_ADDRESS:
			outpw(REG_USBD_ADDR, _usbd_address);
			break;

		case USBR_SET_CONFIGURATION:
//MSG_DEBUG("update\n");
#ifdef USE_EPA_B
			outpw(REG_USBD_EPA_RSP_SC, EP_TOGGLE);
			outpw(REG_USBD_EPB_RSP_SC, EP_TOGGLE);
#endif
#ifdef USE_EPC_D
			outpw(REG_USBD_EPC_RSP_SC, EP_TOGGLE);
			outpw(REG_USBD_EPD_RSP_SC, EP_TOGGLE);
#endif
#ifdef USE_EPE_F
			outpw(REG_USBD_EPE_RSP_SC, EP_TOGGLE);
			outpw(REG_USBD_EPF_RSP_SC, EP_TOGGLE);
#endif
			break;

		case USBR_SET_INTERFACE:
			break;

		case USBR_SET_FEATURE:
			if(_usbd_haltep0 == HALT)
				outpw(REG_USBD_CEP_CTRL_STAT, CEP_SEND_STALL);
			else if(_usbd_haltep1 == HALT)
			{
#ifdef USE_EPA_B
				outpw(REG_USBD_EPA_RSP_SC, EP_HALT);
#endif
#ifdef USE_EPC_D
				outpw(REG_USBD_EPC_RSP_SC, EP_HALT);
#endif
#ifdef USE_EPE_F
				outpw(REG_USBD_EPE_RSP_SC, EP_HALT);
#endif
			}
			else if(_usbd_haltep2 == HALT)
			{
#ifdef USE_EPA_B
				outpw(REG_USBD_EPB_RSP_SC, EP_HALT);
#endif
#ifdef USE_EPC_D
				outpw(REG_USBD_EPD_RSP_SC, EP_HALT);
#endif
#ifdef USE_EPE_F
				outpw(REG_USBD_EPF_RSP_SC, EP_HALT);
#endif
			}
			else if(enableremotewakeup == 1)
			{
				enableremotewakeup = 0;
				remotewakeup = 1;
			}
#if 0			
			else if(enabletestmode == 1)
			{
				enabletestmode = 0;
				if(testselector == TEST_J)
					outpw(REG_USBD_TEST, TEST_J);
				else if(testselector==TEST_K)
					outpw(REG_USBD_TEST, TEST_K);
				else if(testselector==TEST_SE0_NAK)
					outpw(REG_USBD_TEST, TEST_SE0_NAK);
				else if(testselector==TEST_PACKET)
					outpw(REG_USBD_TEST, TEST_PACKET);
				else if(testselector==TEST_FORCE_ENABLE)
					outpw(REG_USBD_TEST, TEST_FORCE_ENABLE);
			}
#endif			
			break;

		case USBR_CLEAR_FEATURE:
			if(_usbd_unhaltep == 1 && _usbd_haltep1 == HALT)
			{
#ifdef USE_EPA_B
				outpw(REG_USBD_EPA_RSP_SC, 0x0);
				outpw(REG_USBD_EPA_RSP_SC, EP_TOGGLE);
#endif
#ifdef USE_EPC_D
				outpw(REG_USBD_EPC_RSP_SC, 0x0);
				outpw(REG_USBD_EPC_RSP_SC, EP_TOGGLE);
#endif
#ifdef USE_EPE_F
				outpw(REG_USBD_EPE_RSP_SC, 0x0);
				outpw(REG_USBD_EPE_RSP_SC, EP_TOGGLE);
#endif
				_usbd_haltep1 = UNHALT; 
				_usbd_unhaltep = 0xff;
			}
			if(_usbd_unhaltep == 2 && _usbd_haltep2 == HALT)
			{
#ifdef USE_EPA_B
				outpw(REG_USBD_EPB_RSP_SC, 0x0);
				outpw(REG_USBD_EPB_RSP_SC, EP_TOGGLE);
#endif
#ifdef USE_EPC_D
				outpw(REG_USBD_EPD_RSP_SC, 0x0);
				outpw(REG_USBD_EPD_RSP_SC, EP_TOGGLE);
#endif
#ifdef USE_EPE_F
				outpw(REG_USBD_EPF_RSP_SC, 0x0);
				outpw(REG_USBD_EPF_RSP_SC, EP_TOGGLE);
#endif
				_usbd_haltep2 = UNHALT; // just for changing the haltep value
				_usbd_unhaltep = 0xff;
			}
			else if(disableremotewakeup == 1)
			{
				disableremotewakeup=0;
				remotewakeup=0;
			}
			break;
		
		default:
			break;
	}
}

extern UINT8 volatile Mass_LUN;
void usbd_send_descriptor()
{
	UINT32 temp_cnt;
	//UINT16 volatile data;
	int volatile i;
	UINT16 *ptr;

	if ((GET_DEV_Flag == 1) || (GET_QUL_Flag == 1) || (GET_CFG_Flag == 1) || 
		(GET_OSCFG_Flag == 1) || (GET_STR_Flag == 1) || (CLASS_CMD_Flag == 1) ||
		(usbdGetConfig == 1) || (usbdGetInterface == 1) || (usbdGetStatus == 1))
	{
		if (_usbd_remlen_flag == 0)
		{
			if (GET_DEV_Flag == 1)
				ptr = _DeviceDescriptor;
			else if (GET_QUL_Flag == 1)
				ptr = _QualifierDescriptor;
			else if (GET_CFG_Flag == 1)
			{
				if (_usbd_speedset == 2)
					ptr = _ConfigurationBlock;
				else if (_usbd_speedset == 1)
					ptr = _ConfigurationBlockFull;
			}
			else if (GET_OSCFG_Flag == 1)
				ptr = _OSConfigurationBlock;
			else if (GET_STR_Flag == 1)
			{
				if ((_usb_cmd_pkt.wValue & 0xff) == 0)
					ptr = _StringDescriptor0;
				else if ((_usb_cmd_pkt.wValue & 0xff) == 1)
					ptr = _StringDescriptor1;
				else if ((_usb_cmd_pkt.wValue & 0xff) == 2)
					ptr = _StringDescriptor2;
				else if ((_usb_cmd_pkt.wValue & 0xff) == 3)
					ptr = _StringDescriptor3;
			}
			else if (CLASS_CMD_Flag == 1)
			{
				outpb(REG_USBD_CEP_DATA_BUF, Mass_LUN-1);
				outpw(REG_USBD_IN_TRNSFR_CNT, 1);
				return;
			}
			else if (usbdGetConfig == 1)
			{
				outpb(REG_USBD_CEP_DATA_BUF, _usbd_confsel);
				outpw(REG_USBD_IN_TRNSFR_CNT, 1);
				return;
			}
			else if (usbdGetInterface == 1)
			{
				outpb(REG_USBD_CEP_DATA_BUF, _usbd_altsel);
				outpw(REG_USBD_IN_TRNSFR_CNT, 1);
				return;
			}
			else if (usbdGetStatus == 1)
			{
				outpw(REG_USBD_CEP_DATA_BUF, usbdGetStatusData);
				outpw(REG_USBD_IN_TRNSFR_CNT, 2);
				return;
			}
		}
		else
			ptr = _usbd_ptr;

		if (_usb_cmd_pkt.wLength > 0x40)
		{
			_usbd_remlen_flag = 1;
			_usbd_remlen = _usb_cmd_pkt.wLength - 0x40;
			_usb_cmd_pkt.wLength = 0x40;
		}
		else if (_usbd_remlen != 0)
		{
			_usbd_remlen_flag = 0;
			_usb_cmd_pkt.wLength = _usbd_remlen;
			_usbd_remlen = 0;
		}
		else
		{
			_usbd_remlen_flag = 0;
			_usbd_remlen = 0;
		}

		temp_cnt = _usb_cmd_pkt.wLength / 2;

		for (i=0; i<temp_cnt; i++)
			outpw(REG_USBD_CEP_DATA_BUF, *ptr++);

		if ((_usb_cmd_pkt.wLength % 2) != 0)
			outpb(REG_USBD_CEP_DATA_BUF, *ptr & 0xff);

		if (_usbd_remlen_flag)
			_usbd_ptr = ptr;

//MSG_DEBUG("desc[%d]\n", _usb_cmd_pkt.wLength);
		outpw(REG_USBD_IN_TRNSFR_CNT, _usb_cmd_pkt.wLength);
	}
}

void usbd_control_packet()
{
	UINT32	temp;
	BOOL	ReqErr;
	
	temp = inpw(REG_USBD_SETUP1_0);
	_usb_cmd_pkt.bmRequestType = (UINT8)temp & 0xff;
	_usb_cmd_pkt.bRequest = (UINT8)(temp >> 8) & 0xff;
	_usb_cmd_pkt.wValue = (UINT16)inpw(REG_USBD_SETUP3_2);
	_usb_cmd_pkt.wIndex = (UINT16)inpw(REG_USBD_SETUP5_4);
	_usb_cmd_pkt.wLength = (UINT16)inpw(REG_USBD_SETUP7_6);

	if ((_usb_cmd_pkt.bmRequestType == 0xa1) && (_usb_cmd_pkt.bRequest == 0xfe))
	{
		// clear flags
		usbdClearAllFlags();
		CLASS_CMD_Flag = 1;

		outpw(REG_USBD_CEP_IRQ_STAT, 0x008);
		outpw(REG_USBD_CEP_IRQ_ENB, 0x008);		//suppkt int ,status and in token
	}else if ((_usb_cmd_pkt.bmRequestType == 0x21) && (_usb_cmd_pkt.bRequest == 0xff))	// MSC Reset 
	{
		UsbResetDma();
		// clear flags
		usbdClearAllFlags();
	
		errorFlagCBW = 0;
		Bulk_First_Flag=0;

		_usbd_haltep1 = UNHALT; 
		_usbd_haltep2 = UNHALT; 
		_usbd_unhaltep = 4;

		outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
		outpw(REG_USBD_CEP_CTRL_STAT, CEP_NAK_CLEAR);	//clear nak so that sts stage is complete
		outpw(REG_USBD_CEP_IRQ_ENB, 0x400);	
		return;
	}

	switch (_usb_cmd_pkt.bRequest)
	{
		case USBR_GET_DESCRIPTOR:
			ReqErr = ((_usb_cmd_pkt.bmRequestType == 0x80) && ((_usb_cmd_pkt.wValue & 0xf000) == 0) 
			&& ((_usb_cmd_pkt.wValue & 0x80) == 0)) ? 0 : 1;

			if(ReqErr==1)
			{ 
				MSG_DEBUG("GET_DESCRIPTOR => 0[%x], 2[%x], 4[%x], 6[%x]\n", inpw(REG_USBD_SETUP1_0), 
				inpw(REG_USBD_SETUP3_2), inpw(REG_USBD_SETUP5_4), inpw(REG_USBD_SETUP7_6));
				break;	//break this switch loop
			}

			switch	((_usb_cmd_pkt.wValue & 0xf00) >> 8) 
			{  //high byte contains desc type so need to shift???
				case USB_DT_DEVICE:
					// clear flags
					usbdClearAllFlags();

					GET_DEV_Flag = 1;
					if (_usb_cmd_pkt.wLength > DEVICE_DSCPT_LEN)
						_usb_cmd_pkt.wLength = DEVICE_DSCPT_LEN;
					break;

				case USB_DT_CONFIG:
					// clear flags
					usbdClearAllFlags();

					GET_CFG_Flag = 1;
					if (_usb_cmd_pkt.wLength > CONFIG_DSCPT_LEN)
						_usb_cmd_pkt.wLength = CONFIG_DSCPT_LEN;
					break;

				case USB_DT_QUALIFIER:	// high-speed operation
					// clear flags
					usbdClearAllFlags();

					GET_QUL_Flag = 1;
					if (_usb_cmd_pkt.wLength > QUALIFIER_DSCPT_LEN)
						_usb_cmd_pkt.wLength = QUALIFIER_DSCPT_LEN;
					break;

				case USB_DT_OSCONFIG:	// other speed configuration
					// clear flags
					usbdClearAllFlags();

					GET_OSCFG_Flag = 1;
					if (_usb_cmd_pkt.wLength > OSCONFIG_DSCPT_LEN)
						_usb_cmd_pkt.wLength = OSCONFIG_DSCPT_LEN;
					break;

				case USB_DT_STRING:
					// clear flags
					usbdClearAllFlags();

					GET_STR_Flag = 1;
					if ((_usb_cmd_pkt.wValue & 0xff) == 0)
					{
						if (_usb_cmd_pkt.wLength > STR0_DSCPT_LEN)
							_usb_cmd_pkt.wLength = STR0_DSCPT_LEN;
					}
					else if ((_usb_cmd_pkt.wValue & 0xff) == 1)
					{
						if (_usb_cmd_pkt.wLength > STR1_DSCPT_LEN)
							_usb_cmd_pkt.wLength = STR1_DSCPT_LEN;
					}
					else if ((_usb_cmd_pkt.wValue & 0xff) == 2)
					{
						if (_usb_cmd_pkt.wLength > STR2_DSCPT_LEN)
							_usb_cmd_pkt.wLength = STR2_DSCPT_LEN;
					}
					else if ((_usb_cmd_pkt.wValue & 0xff) == 3)
					{
						if (_usb_cmd_pkt.wLength > STR3_DSCPT_LEN)
							_usb_cmd_pkt.wLength = STR3_DSCPT_LEN;
					}
					break;

				default:
					ReqErr=1;
					break;
			}	//end of switch
			if (ReqErr == 0)
			{
				outpw(REG_USBD_CEP_IRQ_STAT, 0x008);
				outpw(REG_USBD_CEP_IRQ_ENB, 0x008);		//suppkt int ,status and in token
			}
			break;

		case USBR_SET_ADDRESS:
			ReqErr = ((_usb_cmd_pkt.bmRequestType == 0) && ((_usb_cmd_pkt.wValue & 0xff00) == 0)
			 && (_usb_cmd_pkt.wIndex == 0) && (_usb_cmd_pkt.wLength == 0)) ? 0 : 1;

			if ((_usb_cmd_pkt.wValue & 0xffff) > 0x7f)	//within 7f
			{
				ReqErr=1;	//Devaddr > 127
				MSG_DEBUG("ERROR -  Request Error - Device address greater than 127\n");
			}

			if (_usbd_devstate == 3)
			{
				ReqErr=1;	//Dev is configured
				MSG_DEBUG("ERROR - Request Error - Device is already in configure state\n");
			}

			if (ReqErr==1) 
			{
				MSG_DEBUG("ERROR - CepEvHndlr:USBR_SET_ADDRESS <= Request Error\n");
				break;		//break this switch loop
			}

			if(_usbd_devstate == 2)
			{
				if(_usb_cmd_pkt.wValue == 0)
					_usbd_devstate = 1;		//enter default state
				_usbd_address = _usb_cmd_pkt.wValue;	//if wval !=0,use new address	
			}

			if(_usbd_devstate == 1)
			{
				if(_usb_cmd_pkt.wValue != 0)
				{//enter addr state whether to write or not NOW!!!
					_usbd_address = _usb_cmd_pkt.wValue;
					_usbd_devstate = 2;
				}
			}
			outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
			outpw(REG_USBD_CEP_CTRL_STAT, CEP_NAK_CLEAR);	//clear nak so that sts stage is complete
			outpw(REG_USBD_CEP_IRQ_ENB, 0x400);		// enable status complete interrupt
			break;

		case USBR_GET_CONFIGURATION:
			ReqErr = ((_usb_cmd_pkt.bmRequestType == 0x80) && (_usb_cmd_pkt.wValue == 0) &&
			(_usb_cmd_pkt.wIndex == 0) && (_usb_cmd_pkt.wLength == 0x1) ) ? 0 : 1;

			if (ReqErr==1)
			{
				MSG_DEBUG("ERROR - CepEvHndlr:USBR_GET_CONFIGURATION <= Request Error\n");
				break;	//break this switch loop
			}

			usbdClearAllFlags();
			usbdGetConfig=1;

			outpw(REG_USBD_CEP_IRQ_STAT, 0x008);
			outpw(REG_USBD_CEP_IRQ_ENB, 0x008);		//status and in token
			break;

		case USBR_SET_CONFIGURATION:
			ReqErr = ((_usb_cmd_pkt.bmRequestType == 0) && ((_usb_cmd_pkt.wValue & 0xff00) == 0) &&
			((_usb_cmd_pkt.wValue & 0x80) == 0) && (_usb_cmd_pkt.wIndex == 0) && 
			(_usb_cmd_pkt.wLength == 0)) ? 0 : 1;

			if (_usbd_devstate == 1)
			{
				MSG_DEBUG("ERROR - Device is in Default state\n");
				ReqErr=1;
			}

			if ((_usb_cmd_pkt.wValue != 1) && (_usb_cmd_pkt.wValue != 0) )  //Only configuration one is supported
			{
				MSG_DEBUG("ERROR - Configuration choosed is invalid\n");
				ReqErr=1;
			}
					
			if(ReqErr==1) 
			{
				MSG_DEBUG("ERROR - CepEvHndlr:USBR_SET_CONFIGURATION <= Request Error\n");
				break;	//break this switch loop
			}

			if (_usb_cmd_pkt.wValue == 0)
			{
				_usbd_confsel = 0;
				_usbd_devstate = 2;
			}
			else
			{
				_usbd_confsel = _usb_cmd_pkt.wValue;
				_usbd_devstate = 3;
			}
			outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
			outpw(REG_USBD_CEP_CTRL_STAT, CEP_NAK_CLEAR);	//clear nak so that sts stage is complete
			outpw(REG_USBD_CEP_IRQ_ENB, 0x400);		//status and in token
			break;

		case USBR_GET_INTERFACE:
			ReqErr = ((_usb_cmd_pkt.bmRequestType == 0x81) && (_usb_cmd_pkt.wValue == 0) &&
			(_usb_cmd_pkt.wIndex == 0) && (_usb_cmd_pkt.wLength == 0x1)) ? 0 : 1;

			if ((_usbd_devstate == 1) || (_usbd_devstate == 2))
			{
				MSG_DEBUG("ERROR - Device state is not valid\n");
				ReqErr=1;
			}

			if(ReqErr == 1)
			{
				MSG_DEBUG("ERROR - CepEvHndlr:USBR_GET_INTERFACE <= Request Error\n");
				break;	//break this switch loop
			}

			usbdClearAllFlags();
			usbdGetInterface=1;

			outpw(REG_USBD_CEP_IRQ_STAT, 0x008);
			outpw(REG_USBD_CEP_IRQ_ENB, 0x008);		//suppkt int ,status and in token
			break;

		case USBR_SET_INTERFACE:
			ReqErr = ((_usb_cmd_pkt.bmRequestType == 0x1) && ((_usb_cmd_pkt.wValue & 0xff80) == 0) 
			&& ((_usb_cmd_pkt.wIndex & 0xfff0) == 0) && (_usb_cmd_pkt.wLength == 0)) ? 0 : 1;

			if ((_usbd_devstate == 0x3) && (_usb_cmd_pkt.wIndex == 0x0) && (_usb_cmd_pkt.wValue == 0x0))
			{
				ReqErr=0;
				MSG_DEBUG("interface choosen is already is use, so stall was not sent\n");
			}
			else
			{
				MSG_DEBUG("ERROR - Choosen interface was not supported\n");
				ReqErr=1;
			}

			if (ReqErr == 1)
			{
				MSG_DEBUG("CepEvHndlr:USBR_SET_INTERFACE <= Request Error\n");
				break;	//break this switch loop
			}
			_usbd_altsel = _usb_cmd_pkt.wValue;
			outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
			outpw(REG_USBD_CEP_CTRL_STAT, CEP_NAK_CLEAR);	//clear nak so that sts stage is complete
			outpw(REG_USBD_CEP_IRQ_ENB, 0x400);		//suppkt int ,status and in token
			break;

		case USBR_SET_FEATURE:
MSG_DEBUG("\nUSBR_SET_FEATURE\n\n");
			//ReqErr = (((_usb_cmd_pkt.bmRequestType & 0xfc) == 0) && ((_usb_cmd_pkt.wValue & 0xfffc) == 0) 
			//&& ((_usb_cmd_pkt.wIndex & 0xff00) == 0) && (_usb_cmd_pkt.wLength == 0)) ? 0 : 1;

			if (_usbd_devstate == 1)
			{
				if((_usb_cmd_pkt.bmRequestType & 0x3) == 0x0) // Receipent is Device
				{
					if((_usb_cmd_pkt.wValue & 0x3) == TEST_MODE)
					{
						enabletestmode = 1;
						testselector = (_usb_cmd_pkt.wIndex >> 8);
						outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
						outpw(REG_USBD_CEP_IRQ_ENB, 0x400);
					}
				}
				else
				{
					MSG_DEBUG("ERROR - Device is in Default State\n");
					ReqErr=1;
				}
			}

			if (_usbd_devstate == 2)
			{
				if ((_usb_cmd_pkt.bmRequestType & 0x3 == 2) && ((_usb_cmd_pkt.wIndex & 0xff) != 0))	//ep but not cep
				{
					MSG_DEBUG("ERROR - Device is in Addressed State, but for noncep\n");
					ReqErr =1;
				}
				else if ((_usb_cmd_pkt.bmRequestType & 0x3) == 0x1)
				{
					MSG_DEBUG("ERROR - Device is in Addressed State, but for interface\n");
					ReqErr=1;
				}
			}

			if (ReqErr == 1) 
			{
				MSG_DEBUG("CepEvHndlr:USBR_SET_FEATURE <= Request Error\n");
				break;	//break this switch loop
			}

			//check if recipient and wvalue are appropriate
			switch(_usb_cmd_pkt.bmRequestType & 0x3)
			{
				case 0:		//device
					if ((_usb_cmd_pkt.wValue & 0x3) == DEVICE_REMOTE_WAKEUP)
						enableremotewakeup = 1;
					else if((_usb_cmd_pkt.wValue & 0x3) == TEST_MODE)
					{
						enabletestmode = 1;
						testselector = (_usb_cmd_pkt.wIndex >> 8);
					}
					else
					{
						MSG_DEBUG("ERROR - No such feature for device\n");
						ReqErr=1;
					}
					break;

				case 1:		//interface
					break;

				case 2:		//endpoint
					if((_usb_cmd_pkt.wValue & 0x3) == ENDPOINT_HALT)
					{
						if((_usb_cmd_pkt.wIndex & 0x3) == 0) //endPoint zero
						{
							_usbd_haltep0 = HALT;
						}
						else if((_usb_cmd_pkt.wIndex & 0x3) == 1) //endPoint one
						{
							_usbd_haltep1 = HALT;
						}
						else if((_usb_cmd_pkt.wIndex & 0x3) == 2) //endPoint two
						{
							_usbd_haltep2 = HALT;
						}
						else
						{
							MSG_DEBUG("ERROR - Selected endpoint was not present\n");
							ReqErr=1;
						}
					}
					else
					{
						MSG_DEBUG("ERROR - Neither device,endpoint nor interface was choosen\n");
						ReqErr=1;
					}
					break;

				default:
					break;
			}//device
			outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
			outpw(REG_USBD_CEP_CTRL_STAT, CEP_NAK_CLEAR);	//clear nak so that sts stage is complete
			outpw(REG_USBD_CEP_IRQ_ENB, 0x400);		//suppkt int ,status and in token
			break;

		case USBR_CLEAR_FEATURE:
MSG_DEBUG("\nUSBR_CLEAR_FEATURE\n\n");
			ReqErr = (((_usb_cmd_pkt.bmRequestType & 0xfc) == 0) && ((_usb_cmd_pkt.wValue & 0xfffc) == 0) 
			&& ((_usb_cmd_pkt.wIndex & 0xff00) == 0) && (_usb_cmd_pkt.wLength == 0)) ? 0 : 1;

			if (_usbd_devstate == 1) 
			{
				MSG_DEBUG("ERROR - Device is in default state\n");
				ReqErr =1;
			}

			if (_usbd_devstate == 2)
			{
				if((_usb_cmd_pkt.bmRequestType == 2) && (_usb_cmd_pkt.wIndex != 0)) //ep but not cep
				{
					MSG_DEBUG("ERROR - Device is in Addressed State, but for noncep\n");
					ReqErr =1;
				}
				else if(_usb_cmd_pkt.bmRequestType == 0x1)	//recip is interface
				{
					MSG_DEBUG("ERROR - Device is in Addressed State, but for interface\n");
					ReqErr=1;
				}
			}

			if(ReqErr == 1) 
			{
				MSG_DEBUG("ERROR - CepEvHndlr:USBR_CLEAR_FEATURE <= Request Error\n");
				break;	//break this switch loop
			}

			switch((_usb_cmd_pkt.bmRequestType & 0x3))
			{
				case 0:		//device 
					if((_usb_cmd_pkt.wValue & 0x3) == DEVICE_REMOTE_WAKEUP)
						disableremotewakeup = 1;
					else
					{
						MSG_DEBUG("ERROR - No such feature for device\n");
						ReqErr=1;
					}
					break;

				case 1:		//interface
					break;

				case 2:		//endpoint
					if((_usb_cmd_pkt.wValue & 0x3) == ENDPOINT_HALT)
					{
						if((_usb_cmd_pkt.wIndex & 0x3) == 0) //endPoint zero
							_usbd_unhaltep = 0;
						else if((_usb_cmd_pkt.wIndex & 0x3) == 1) //endPoint one
						{
							if (!errorFlagCBW)
								_usbd_unhaltep = 1;

						}
						else if((_usb_cmd_pkt.wIndex & 0x3) == 2) //endPoint two
						{
							if (!errorFlagCBW)
								_usbd_unhaltep = 2;
						}
						else
						{
							MSG_DEBUG("ERROR - endpoint choosen was not supported\n");
							ReqErr=1;
						}
					}
					else
					{
						MSG_DEBUG("ERROR - Neither device,interface nor endpoint was choosen\n");
						ReqErr=1;
					}
					break;

				default:
					break;
			}	//device

			outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
			outpw(REG_USBD_CEP_CTRL_STAT, CEP_NAK_CLEAR);	//clear nak so that sts stage is complete
			outpw(REG_USBD_CEP_IRQ_ENB, 0x400);		//suppkt int ,status and in token
		break;

		case USBR_GET_STATUS:
MSG_DEBUG("\nUSBR_GET_STATUS\n\n");
			//check if this is valid
			ReqErr = (((_usb_cmd_pkt.bmRequestType & 0xfc) == 0x80) && (_usb_cmd_pkt.wValue == 0) 
			&& ((_usb_cmd_pkt.wIndex & 0xff00) == 0) && (_usb_cmd_pkt.wLength == 0x2)) ? 0 : 1;

			if (_usbd_devstate == 1)
			{
				MSG_DEBUG("ERROR - Device is in default State\n");
				ReqErr =1;
			}
			if (_usbd_devstate == 2)
			{
				if ((_usb_cmd_pkt.bmRequestType & 0x3 == 0x2) && (_usb_cmd_pkt.wIndex != 0))
				{
					MSG_DEBUG("ERROR - Device is in Addressed State, but for noncep\n");
					ReqErr =1;
				}
				else if (_usb_cmd_pkt.bmRequestType & 0x3 == 0x1)
				{
					MSG_DEBUG("ERROR - Device is in Addressed State, but for interface\n");
					ReqErr =1;
				}
			}

			if (ReqErr == 1)
			{
				MSG_DEBUG("ERROR - CepEvHndlr:USBR_GET_STATUS <= Request Error\n");
				break;	//break this switch loop
			}

			usbdClearAllFlags();
			usbdGetStatus=1;

			switch (_usb_cmd_pkt.bmRequestType & 0x3)
			{
				case 0:	// device
					MSG_DEBUG("value of dx->remotewakeup is %d\n", remotewakeup);
					if (remotewakeup == 1)
						usbdGetStatusData = 0x3;
					else 
						usbdGetStatusData = 0x1;
					break;

				case 1:	//interface
					if (_usb_cmd_pkt.wIndex == 0)
					{
						MSG_DEBUG("Status of interface zero\n");
						usbdGetStatusData = 0;
					}
					else
					{
						MSG_DEBUG("Error - Status of interface non zero\n");
						ReqErr=1;
					}
					break;

				case 2:	//endpoint
					if (_usb_cmd_pkt.wIndex == 0x0)
					{
						MSG_DEBUG("Status of Endpoint zero\n");
						usbdGetStatusData = 0;
					}
					else if (_usb_cmd_pkt.wIndex == 0x81)
					{
						MSG_DEBUG("Status of Endpoint one\n");
						if (_usbd_haltep1 == HALT)
							usbdGetStatusData = 0x1;
						else
							usbdGetStatusData = 0;
					}
					else if (_usb_cmd_pkt.wIndex == 0x2)
					{
						MSG_DEBUG("Status of Endpoint two\n");
						if (_usbd_haltep2 == HALT)
							usbdGetStatusData = 0x1;
						else
							usbdGetStatusData = 0;
					}
					else
					{
						MSG_DEBUG("Error - Status of non-existing Endpoint\n");
						ReqErr=1;
					}
					break;

				default:
					break;
			}
			outpw(REG_USBD_CEP_IRQ_STAT, 0x008);
			outpw(REG_USBD_CEP_IRQ_ENB, 0x008);		//suppkt int ,status and in token
			break;

		default:	// other request
			break;
	}
	if (ReqErr == 1)
	{
		// not supported request, send stall
		outpw(REG_USBD_CEP_CTRL_STAT, CEP_SEND_STALL);
	}
}

void usbd_EP_ISR(UINT32 IrqSt)
{
//printf("EP_ISR: [%x]\n", IrqSt);
	if (IrqSt & EP_BUFF_FULL);
		//MSG_DEBUG("Buffer Full Interrupt\n");

	if (IrqSt & EP_IN_TOK);
		//MSG_DEBUG("In Token Interrupt\n");

	if (IrqSt & EP_DATA_TXD)
	{
		MSG_DEBUG("Data Txd \n");
	}

	if (IrqSt & EP_BUFF_EMPTY);
		//MSG_DEBUG("Buffer Empty Interrupt\n");

	if (IrqSt & EP_SHORT_PKT);
		//MSG_DEBUG("Short Packet Interrupt\n");

	if (IrqSt & EP_OUT_TOK);
		//MSG_DEBUG("Out Token Interrupt\n");

	if (IrqSt & EP_DATA_RXD)
	{
		MSG_DEBUG("Data Rxd\n");
	}

	if (IrqSt & EP_PING_TOK);
		//MSG_DEBUG("Ping Token Interrupt\n");

	if (IrqSt & EP_NAK_SENT);
		//MSG_DEBUG("Nak Sent Interrupt\n");

	if (IrqSt & EP_STALL_SENT);
		//MSG_DEBUG("Stall Sent Interrupt\n");

	if (IrqSt & EP_USB_ERR);
		//MSG_DEBUG("USB Error Interrupt\n");
}

void usb_isr(void)
{
	UINT32 volatile IrqStL, IrqEnL, IrqSt, IrqEn;

	IrqStL = inpw(REG_USBD_IRQ_STAT);		/* get interrupt status */
	IrqEnL = inpw(REG_USBD_IRQ_ENB_L);

	if (!(IrqStL & IrqEnL))
	{
		MSG_DEBUG("Not our interrupt!\n");
		return;
	}

	/* USB interrupt */
	if (IrqStL & IRQ_USB_STAT)
	{
		IrqSt = inpw(REG_USBD_USBIRQ_STAT);
		IrqEn = inpw(REG_USBD_IRQ_ENB);

//MSG_DEBUG("INT status[%x], oper[%x]\n", IrqSt, inpw(REG_USBD_OPER));

		if (IrqSt & USB_SOF & IrqEn)
		{
			MSG_DEBUG("SOF Interrupt\n");
			outpw(REG_USBD_USBIRQ_STAT, 0x01);
		}

		if (IrqSt & USB_RST_STS & IrqEn)
		{
			//MSG_DEBUG("Reset Status Interrupt\n");
			_usbd_devstate = 0;
			_usbd_speedset = 0;
			_usbd_address = 0;

			// clear flags
			usbdClearAllFlags();
			USBModeFlag=0;
			_usbd_DMA_Flag=0;
			_usbd_Less_MPS=0;
			Bulk_First_Flag=0;

			UsbResetDma();

			_usbd_devstate = 1;		//default state
			_usbd_address = 0;		//zero

			if (inpw(REG_USBD_OPER) & 0x04)
			{
				MSG_DEBUG("High speed after reset\n");
				_usbd_speedset = 2;		//for high speed
				usbdHighSpeedInit();
			}
			else
			{
				MSG_DEBUG("Full speed after reset\n");
				_usbd_speedset = 1;		//for full speed
				usbdFullSpeedInit();
			}
			outpw(REG_USBD_CEP_IRQ_ENB, 0x002);		//suppkt int

			outpw(REG_USBD_ADDR, 0);
			outpw(REG_USBD_IRQ_ENB, (USB_RST_STS|USB_SUS_REQ|USB_RESUME));
			outpw(REG_USBD_USBIRQ_STAT, 0x02);
			outpw(REG_USBD_CEP_IRQ_STAT, 0xfffc);
		}

		if (IrqSt & USB_RESUME & IrqEn)
		{
			MSG_DEBUG("Resume Interrupt\n");
			_usbd_resume = 1;
			outpw(REG_USBD_IRQ_ENB, (USB_RST_STS|USB_SUS_REQ));
			outpw(REG_USBD_USBIRQ_STAT, 0x04);
		}

		if (IrqSt & USB_SUS_REQ & IrqEn)
		{
			MSG_DEBUG("Suspend Request Interrupt\n");
			_usbd_resume = 0;
			outpw(REG_USBD_IRQ_ENB, (USB_RST_STS | USB_RESUME));
			outpw(REG_USBD_USBIRQ_STAT, 0x08);
		}

		if (IrqSt & USB_HS_SETTLE & IrqEn)
		{
			MSG_DEBUG("Device settled in High speed\n");
			_usbd_devstate = 1;		//default state
			_usbd_speedset = 2;		//for high speed
			_usbd_address = 0;		//zero
			outpw(REG_USBD_CEP_IRQ_ENB, 0x002);
			outpw(REG_USBD_USBIRQ_STAT, 0x10);
		}
		
		if (IrqSt & USB_DMA_REQ & IrqEn)
		{
			_usbd_DMA_Flag = 1;
			outpw(REG_USBD_USBIRQ_STAT, USB_DMA_REQ);

			if (_usbd_DMA_Dir == Ep_Out)
			{
			//	MSG_DEBUG("OUT DMA [%d]\n", _usbd_Less_MPS);
				if (Bulk_First_Flag==1)
					bulkonlycmd=1;
#ifdef USE_EPA_B
				outpw(REG_USBD_EPB_IRQ_ENB, 0x10);
#endif
#ifdef USE_EPC_D
				outpw(REG_USBD_EPD_IRQ_ENB, 0x10);
#endif
#ifdef USE_EPE_F
				outpw(REG_USBD_EPF_IRQ_ENB, 0x10);
#endif
			}
			if (_usbd_DMA_Dir == Ep_In)
			{
				MSG_DEBUG("IN DMA [%d]\n", _usbd_Less_MPS);
				if (_usbd_Less_MPS == 1)
				{
#ifdef USE_EPA_B
					outpw(REG_USBD_EPA_RSP_SC, 0x00000040);	// packet end
#endif
#ifdef USE_EPC_D
					outpw(REG_USBD_EPC_RSP_SC, 0x00000040);	// packet end
#endif
#ifdef USE_EPE_F
					outpw(REG_USBD_EPE_RSP_SC, 0x00000040);	// packet end
#endif
					_usbd_Less_MPS = 0;
				}
			}
		}

		if (IrqSt & USABLE_CLK & IrqEn)
			outpw(REG_USBD_USBIRQ_STAT, 0x40);
			//MSG_DEBUG("Usable Clock Interrupt\n");

		outpw(REG_USBD_IRQ_STAT, IRQ_USB_STAT);	
	}

	if (IrqStL & IRQ_CEP) 
	{
		IrqSt = inpw(REG_USBD_CEP_IRQ_STAT);
		IrqEn = inpw(REG_USBD_CEP_IRQ_ENB);

//MSG_DEBUG("control INT status[%x]\n", IrqSt);

		if (IrqSt & CEP_SUPTOK & IrqEn)
		{
			//MSG_DEBUG("Setup Token Interrupt\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x001);
			return;
		}

		if (IrqSt & CEP_SUPPKT & IrqEn)
		{
			//MSG_DEBUG("Setup\n");
			
			outpw(REG_USBD_CEP_IRQ_STAT, 0x002);
			usbd_control_packet();		
			return;
		}

		if (IrqSt & CEP_OUT_TOK & IrqEn)
		{
			//MSG_DEBUG("Out\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x004);
			outpw(REG_USBD_CEP_IRQ_ENB, 0x400);		// suppkt int//enb sts completion int
			return;
		}

		if (IrqSt & CEP_IN_TOK & IrqEn)
		{
			//MSG_DEBUG("In[%x]\n", IrqSt);
			outpw(REG_USBD_CEP_IRQ_STAT, 0x008);
			if (!(IrqSt & CEP_STS_END))
			{
				outpw(REG_USBD_CEP_IRQ_STAT, 0x020);
				outpw(REG_USBD_CEP_IRQ_ENB, 0x020);
				usbd_send_descriptor();
			}
			else
			{
				outpw(REG_USBD_CEP_IRQ_STAT, 0x020);
				outpw(REG_USBD_CEP_IRQ_ENB, 0x420);
			}
			//outpw(REG_USBD_CEP_IRQ_STAT, 0x008);
			return;
		}

		if (IrqSt & CEP_PING_TOK & IrqEn)
		{
			MSG_DEBUG("Ping\n");
			//outpw(REG_USBD_CEP_IRQ_ENB, 0x402);		// suppkt int//enb sts completion int
			outpw(REG_USBD_CEP_IRQ_STAT, 0x010);
			return;
		}

		if (IrqSt & CEP_DATA_TXD & IrqEn)
		{
			//MSG_DEBUG("Txd\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
			outpw(REG_USBD_CEP_CTRL_STAT, CEP_NAK_CLEAR);	// clear nak so that sts stage is complete
			outpw(REG_USBD_CEP_IRQ_ENB, 0x400);		// suppkt int//enb sts completion int
			outpw(REG_USBD_CEP_IRQ_STAT, 0x020);
			return;
		}

		if (IrqSt & CEP_DATA_RXD & IrqEn)
		{
			//MSG_DEBUG("Rxd\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x440);
			outpw(REG_USBD_CEP_CTRL_STAT, CEP_NAK_CLEAR);	// clear nak so that sts stage is complete
			outpw(REG_USBD_CEP_IRQ_ENB, 0x43e);		// suppkt int//enb sts completion int
			return;
		}

		if (IrqSt & CEP_NAK_SENT & IrqEn)
		{
			MSG_DEBUG("NAK Sent Interrupt\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x080);
			return;
		}

		if (IrqSt & CEP_STALL_SENT & IrqEn)
		{
			MSG_DEBUG("STALL Sent Interrupt\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x100);
			return;
		}

		if (IrqSt & CEP_USB_ERR & IrqEn)
		{
			MSG_DEBUG("USB Error Interrupt\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x200);
			return;
		}

		if (IrqSt & CEP_STS_END & IrqEn)
		{
			//MSG_DEBUG("Status\n");
			
			usbd_update_device();
			outpw(REG_USBD_CEP_IRQ_STAT, 0x400);
			if (CLASS_CMD_Flag || _usbd_resume || GET_DEV_Flag)
				USBModeFlag = 1;
			//MSG_DEBUG("Status [%x]\n", inpw(REG_USBD_CEP_IRQ_STAT));
			outpw(REG_USBD_CEP_IRQ_ENB, 0x002);
			return;
		}

		if (IrqSt & CEP_BUFF_FULL & IrqEn)
		{
			MSG_DEBUG("Buffer Full Interrupt\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x800);
			return;
		}

		if (IrqSt & CEP_BUFF_EMPTY & IrqEn)
		{
			MSG_DEBUG("Buffer Empty Interrupt\n");
			outpw(REG_USBD_CEP_IRQ_STAT, 0x1000);
			return;
		}
		outpw(REG_USBD_IRQ_STAT, IRQ_CEP);
	}

	if (IrqStL & IRQ_NCEP) 
	{
		if (IrqStL & 0x04)
		{
			IrqSt = inpw(REG_USBD_EPA_IRQ_STAT);
			IrqEn = inpw(REG_USBD_EPA_IRQ_ENB);
			//MSG_DEBUG(" Interrupt from Endpoint A m[%x], s[%x]\n", IrqEn, IrqSt);
			
			outpw(REG_USBD_EPA_IRQ_STAT, 0x40);	//data pkt transmited
			outpw(REG_USBD_EPA_IRQ_STAT, IrqSt);
		}
		
		if (IrqStL & 0x08)
		{
			IrqSt = inpw(REG_USBD_EPB_IRQ_STAT);
			IrqEn = inpw(REG_USBD_EPB_IRQ_ENB);
			//MSG_DEBUG(" Interrupt from Endpoint B m[%x], s[%x]\n", IrqEn, IrqSt);

			outpw(REG_USBD_EPB_IRQ_ENB, 0x0);
			outpw(REG_USBD_EPB_IRQ_STAT, IrqSt);
		}

		if (IrqStL & 0x10)
		{
			MSG_DEBUG(" Interrupt from Endpoint C \n");
			IrqSt = inpw(REG_USBD_EPC_IRQ_STAT);
			IrqEn = inpw(REG_USBD_EPC_IRQ_ENB);

			outpw(REG_USBD_EPC_IRQ_STAT, 0x40);	//data pkt transmited
			outpw(REG_USBD_EPC_IRQ_STAT, IrqSt);
		}

		if (IrqStL & 0x20)
		{
			MSG_DEBUG(" Interrupt from Endpoint D \n");
			IrqSt = inpw(REG_USBD_EPD_IRQ_STAT);
			IrqEn = inpw(REG_USBD_EPD_IRQ_ENB);

			outpw(REG_USBD_EPD_IRQ_ENB, 0x0);
			outpw(REG_USBD_EPD_IRQ_STAT, IrqSt);
		}

		if (IrqStL & 0x40)
		{
			MSG_DEBUG(" Interrupt from Endpoint E \n");
			IrqSt = inpw(REG_USBD_EPE_IRQ_STAT);
			IrqEn = inpw(REG_USBD_EPE_IRQ_ENB);

			outpw(REG_USBD_EPE_IRQ_STAT, 0x40);	//data pkt transmited
			outpw(REG_USBD_EPE_IRQ_STAT, IrqSt);
		}

		if (IrqStL & 0x80)
		{
			MSG_DEBUG(" Interrupt from Endpoint F \n");
			IrqSt = inpw(REG_USBD_EPF_IRQ_STAT);
			IrqEn = inpw(REG_USBD_EPF_IRQ_ENB);

			outpw(REG_USBD_EPF_IRQ_ENB, 0x0);
			outpw(REG_USBD_EPF_IRQ_STAT, IrqSt);
		}
		outpw(REG_USBD_IRQ_STAT, IRQ_NCEP);
	}
}

void SDRAM_USB_Transfer(UINT32 DRAM_Addr ,UINT32 Tran_Size)
{
	unsigned int volatile reg;

	if (Tran_Size != 0)
	{
		outpw(REG_USBD_IRQ_ENB, (USB_DMA_REQ | USB_RST_STS | USB_SUS_REQ));
		outpw(REG_USBD_AHB_DMA_ADDR, DRAM_Addr);
		outpw(REG_USBD_DMA_CNT, Tran_Size);
		_usbd_DMA_Flag=0;
		reg = inpw(REG_USBD_DMA_CTRL_STS);
		if ((reg & 0x40) != 0x40)
		{
#ifdef USBD_SCATTER_GETHER
			if (!_usbd_Less_MPS)
				outpw(REG_USBD_DMA_CTRL_STS, reg|0x00000070);
			else
				outpw(REG_USBD_DMA_CTRL_STS, reg|0x00000020);
#else
			outpw(REG_USBD_DMA_CTRL_STS, reg|0x00000020);
#endif
		}
		while((USBModeFlag)&&(_usbd_DMA_Flag==0));
	}
}

/* USB means usb host, sdram->host=> bulk in */
void SDRAM2USB_Bulk(UINT32 DRAM_Addr ,UINT32 Tran_Size)
{
	unsigned int volatile count=0;
	int volatile i=0, loop;
	UINT32 volatile addr, len;

	MSG_DEBUG("SDRAM2USB_Bulk: addr[%x], size[%d]\n", DRAM_Addr, Tran_Size);

	_usbd_DMA_Dir = Ep_In;
   	outpw(REG_USBD_DMA_CTRL_STS, (inpw(REG_USBD_DMA_CTRL_STS)&0xe0) | 0x11);	// bulk in, dma read, ep1

	loop = Tran_Size / USBD_DMA_LEN;
	for (i=0; i<loop; i++)
	{
#ifdef USE_EPA_B
		outpw(REG_USBD_EPA_IRQ_ENB, 0x08);
#endif
#ifdef USE_EPC_D
		outpw(REG_USBD_EPC_IRQ_ENB, 0x08);
#endif
#ifdef USE_EPE_F
		outpw(REG_USBD_EPE_IRQ_ENB, 0x08);
#endif
		_usbd_Less_MPS = 0;
		while(1)
		{
#ifdef USE_EPA_B
			if (inpw(REG_USBD_EPA_IRQ_STAT) & 0x02)
#endif
#ifdef USE_EPC_D
			if (inpw(REG_USBD_EPC_IRQ_STAT) & 0x02)
#endif
#ifdef USE_EPE_F
			if (inpw(REG_USBD_EPE_IRQ_STAT) & 0x02)
#endif
			{
#ifdef USBD_SCATTER_GETHER
				usbdTransferAddress((DRAM_Addr+i*USBD_DMA_LEN), USBD_DMA_LEN, TRUE);
				SDRAM_USB_Transfer((UINT32)USBD_DMA_Desc, USBD_DMA_LEN);
#else
		        SDRAM_USB_Transfer(DRAM_Addr+i*USBD_DMA_LEN, USBD_DMA_LEN);
#endif
	        	break;
	        }
        }
	}

	addr = DRAM_Addr + i * USBD_DMA_LEN;
	loop = Tran_Size % USBD_DMA_LEN;
	if (loop != 0)
	{
		count = loop / usbdMaxPacketSize;
		if (count != 0)
		{
#ifdef USE_EPA_B
			outpw(REG_USBD_EPA_IRQ_ENB, 0x08);
#endif
#ifdef USE_EPC_D
			outpw(REG_USBD_EPC_IRQ_ENB, 0x08);
#endif
#ifdef USE_EPE_F
			outpw(REG_USBD_EPE_IRQ_ENB, 0x08);
#endif
			_usbd_Less_MPS = 0;
			while(1)
			{
#ifdef USE_EPA_B
				if (inpw(REG_USBD_EPA_IRQ_STAT) & 0x02)
#endif
#ifdef USE_EPC_D
				if (inpw(REG_USBD_EPC_IRQ_STAT) & 0x02)
#endif
#ifdef USE_EPE_F
				if (inpw(REG_USBD_EPE_IRQ_STAT) & 0x02)
#endif
				{
#ifdef USBD_SCATTER_GETHER
					usbdTransferAddress(addr, usbdMaxPacketSize*count, TRUE);
					SDRAM_USB_Transfer((UINT32)USBD_DMA_Desc, usbdMaxPacketSize*count);
#else
					SDRAM_USB_Transfer(addr, usbdMaxPacketSize*count);
#endif
		        	break;
		        }
	        }
	        addr = addr + count*usbdMaxPacketSize;
		}

		len = loop % usbdMaxPacketSize;
		if (len != 0)
		{
#ifdef USE_EPA_B
			outpw(REG_USBD_EPA_IRQ_ENB, 0x08);
#endif
#ifdef USE_EPC_D
			outpw(REG_USBD_EPC_IRQ_ENB, 0x08);
#endif
#ifdef USE_EPE_F
			outpw(REG_USBD_EPE_IRQ_ENB, 0x08);
#endif
			_usbd_Less_MPS = 1;
			while(1)
			{
#ifdef USE_EPA_B
				if (inpw(REG_USBD_EPA_IRQ_STAT) & 0x02)
#endif
#ifdef USE_EPC_D
				if (inpw(REG_USBD_EPC_IRQ_STAT) & 0x02)
#endif
#ifdef USE_EPE_F
				if (inpw(REG_USBD_EPE_IRQ_STAT) & 0x02)
#endif
				{
			        SDRAM_USB_Transfer(addr, len);
		        	break;
		        }
	        }
		}
	}
}

void ReceiveCBW(UINT32 DRAM_Addr)
{
	UINT32 reg;
	
	_usbd_DMA_Dir = Ep_Out;
   	outpw(REG_USBD_DMA_CTRL_STS, (inpw(REG_USBD_DMA_CTRL_STS) & 0xe0)|0x02);	// bulk out, dma write, ep2

	outpw(REG_USBD_IRQ_ENB, (USB_DMA_REQ | USB_RST_STS | USB_SUS_REQ));
	
	outpw(REG_USBD_AHB_DMA_ADDR, DRAM_Addr);
	outpw(REG_USBD_DMA_CNT, 31);

	_usbd_DMA_Flag=0;
	reg = inpw(REG_USBD_DMA_CTRL_STS);
	if ((reg & 0x40) != 0x40)
	{
#ifdef USBD_SCATTER_GETHER
		if (!_usbd_Less_MPS)
			outpw(REG_USBD_DMA_CTRL_STS, reg|0x00000070);
		else
			outpw(REG_USBD_DMA_CTRL_STS, reg|0x00000020);
#else
		outpw(REG_USBD_DMA_CTRL_STS, reg|0x00000020);
#endif
	}

}

void USB2SDRAM_Bulk(UINT32 DRAM_Addr ,UINT32 Tran_Size)
{
	int volatile i=0, loop;

	MSG_DEBUG("USB2SDRAM_Bulk: addr[%x], size[%d]\n", DRAM_Addr, Tran_Size);

	_usbd_DMA_Dir = Ep_Out;
	_usbd_Less_MPS = 0;
   	outpw(REG_USBD_DMA_CTRL_STS, (inpw(REG_USBD_DMA_CTRL_STS) & 0xe0)|0x02);	// bulk out, dma write, ep2

	loop = Tran_Size / USBD_DMA_LEN;
	for (i=0; i<loop; i++)
	{
#ifdef USBD_SCATTER_GETHER
		usbdTransferAddress((DRAM_Addr+i*USBD_DMA_LEN), USBD_DMA_LEN, FALSE);
		SDRAM_USB_Transfer((UINT32)USBD_DMA_Desc, USBD_DMA_LEN);
#else
		SDRAM_USB_Transfer((DRAM_Addr+i*USBD_DMA_LEN), USBD_DMA_LEN);
#endif
	}

	loop = Tran_Size % USBD_DMA_LEN;
	if (loop != 0)
	{
#ifdef USBD_SCATTER_GETHER
		usbdTransferAddress((DRAM_Addr+i*USBD_DMA_LEN), loop, FALSE);
		SDRAM_USB_Transfer((UINT32)USBD_DMA_Desc, loop);
#else
		SDRAM_USB_Transfer((DRAM_Addr+i*USBD_DMA_LEN), loop);
#endif
	}
}


#ifdef ENABLE_DBUFF
extern UINT8 Storage_Block[2][STORAGE_BUFFER_SIZE];
extern int volatile Card_STS;

void USB2SDRAM_Bulk_DB(INT lun, UINT32 Start_Sec, INT Sector_Cnt, UINT32 Tran_Size)
{
	unsigned int volatile reg;
	UINT32		DRAM_Addr;

	DRAM_Addr =  (UINT32)(Storage_Block[_Mass_DBCtl.work_idx]) | 0x80000000;

	MSG_DEBUG("USB2SDRAM_Bulk_DB: addr[%x], size[%d]\n", DRAM_Addr, Tran_Size);
	
	if (Tran_Size > USBD_DMA_LEN)
	{
		sysprintf("USB2SDRAM_Bulk_DB - Serious error!!\n");
		return;
	}
	
	_usbd_DMA_Dir = Ep_Out;
	_usbd_Less_MPS = 0;
   	outpw(REG_USBD_DMA_CTRL_STS, (inpw(REG_USBD_DMA_CTRL_STS) & 0xe0)|0x02);	// bulk out, dma write, ep2

	if (Tran_Size == 0)
		return;

	outpw(REG_USBD_IRQ_ENB, (USB_DMA_REQ | USB_RST_STS | USB_SUS_REQ));
	outpw(REG_USBD_AHB_DMA_ADDR, DRAM_Addr);
	outpw(REG_USBD_DMA_CNT, Tran_Size);
	_usbd_DMA_Flag=0;
	reg = inpw(REG_USBD_DMA_CTRL_STS);
	outpw(REG_USBD_DMA_CTRL_STS, reg|0x00000020);
	
	if (_Mass_DBCtl.is_queued)
	{
       	Card_STS = MASS_IO_Write(_Mass_DBCtl.lun, _Mass_DBCtl.q_start_sec, 
       							_Mass_DBCtl.q_sec_cnt, 
       							(UINT8 *)((UINT32)Storage_Block[_Mass_DBCtl.q_idx] | 0x80000000));
	}

	while ((USBModeFlag)&&(_usbd_DMA_Flag==0));

	if (_Mass_DBCtl.work_idx == 0)
	{
		_Mass_DBCtl.q_idx    = 0;
		_Mass_DBCtl.work_idx = 1;
	}
	else
	{
		_Mass_DBCtl.q_idx    = 1;
		_Mass_DBCtl.work_idx = 0;
	}
	_Mass_DBCtl.is_queued    = 1;
	_Mass_DBCtl.lun          = lun;
	_Mass_DBCtl.q_start_sec  = Start_Sec;
	_Mass_DBCtl.q_sec_cnt    = Sector_Cnt;
	_Mass_DBCtl.q_time_stamp = sysGetTicks(TIMER0);
}
#endif



void usbdTransferAddress(UINT32 uaddr, UINT32 len, UINT32 IsRead)
{
	UINT32 volatile paddr, loop, remlen, dir=0;
	int volatile i=0;

	loop = len / 4096;

	if (IsRead)
		dir = 0x40000000;

	paddr = uaddr;
	for (i=0; i<loop; i++, paddr+=0x1000)
	{
#ifdef CACHE_ON
		USBD_DMA_Desc[i].uPhyAddress = sysGetPhyPageAddr(paddr);
#else
		USBD_DMA_Desc[i].uPhyAddress = paddr;
#endif
		USBD_DMA_Desc[i].uCountAndDir = dir | 4096;
	}

	remlen = len % 4096;
	if (remlen != 0)
	{
#ifdef CACHE_ON
		USBD_DMA_Desc[i].uPhyAddress = sysGetPhyPageAddr(paddr);
#else
		USBD_DMA_Desc[i].uPhyAddress = paddr;
#endif
		USBD_DMA_Desc[i].uCountAndDir = remlen|0x80000000|dir;
	}
	else if (loop > 0)
		USBD_DMA_Desc[i-1].uCountAndDir = USBD_DMA_Desc[i-1].uCountAndDir|0x80000000;
	
#ifdef CACHE_ON
	sysFlushCache(D_CACHE);
#endif
}

void usbdHighSpeedInit()
{
	MSG_DEBUG("Device is configured for High Speed\n");
	usbdMaxPacketSize = 0x200;
#ifdef USE_EPA_B
	/* bulk in */
	outpw(REG_USBD_EPA_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPA_MPS, 0x00000200);		// mps 512
	outpw(REG_USBD_EPA_CFG, 0x0000001b);		// bulk in ep no 1
	outpw(REG_USBD_EPA_START_ADDR, 0x00000080);
	outpw(REG_USBD_EPA_END_ADDR, 0x000003ff);

	/* bulk out */
	outpw(REG_USBD_EPB_IRQ_ENB, 0x00000010);	// data pkt received  and outtokenb
	outpw(REG_USBD_EPB_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPB_MPS, 0x00000200);		// mps 512
	outpw(REG_USBD_EPB_CFG, 0x00000023);		// bulk out ep no 2
	outpw(REG_USBD_EPB_START_ADDR, 0x00000400);
	outpw(REG_USBD_EPB_END_ADDR, 0x000007ff);
#endif
#ifdef USE_EPC_D
	/* bulk in */
	outpw(REG_USBD_EPC_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPC_MPS, 0x00000200);		// mps 512
	outpw(REG_USBD_EPC_CFG, 0x0000001b);		// bulk in ep no 1
	outpw(REG_USBD_EPC_START_ADDR, 0x00000080);
	outpw(REG_USBD_EPC_END_ADDR, 0x000003ff);

	/* bulk out */
	outpw(REG_USBD_EPD_IRQ_ENB, 0x00000010);	// data pkt received  and outtokenb
	outpw(REG_USBD_EPD_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPD_MPS, 0x00000200);		// mps 512
	outpw(REG_USBD_EPD_CFG, 0x00000023);		// bulk out ep no 2
	outpw(REG_USBD_EPD_START_ADDR, 0x00000400);
	outpw(REG_USBD_EPD_END_ADDR, 0x000007ff);
#endif
#ifdef USE_EPE_F
	/* bulk in */
	outpw(REG_USBD_EPE_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPE_MPS, 0x00000200);		// mps 512
	outpw(REG_USBD_EPE_CFG, 0x0000001b);		// bulk in ep no 1
	outpw(REG_USBD_EPE_START_ADDR, 0x00000080);
	outpw(REG_USBD_EPE_END_ADDR, 0x000003ff);

	/* bulk out */
	outpw(REG_USBD_EPF_IRQ_ENB, 0x00000010);	// data pkt received  and outtokenb
	outpw(REG_USBD_EPF_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPF_MPS, 0x00000200);		// mps 512
	outpw(REG_USBD_EPF_CFG, 0x00000023);		// bulk out ep no 2
	outpw(REG_USBD_EPF_START_ADDR, 0x00000400);
	outpw(REG_USBD_EPF_END_ADDR, 0x000007ff);
#endif
}

void usbdFullSpeedInit()
{
	MSG_DEBUG("Device is configured for Full Speed\n");
	usbdMaxPacketSize = 0x40;
#ifdef USE_EPA_B
	/* bulk in */
	outpw(REG_USBD_EPA_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPA_MPS, 0x00000040);		// mps 64
	outpw(REG_USBD_EPA_CFG, 0x0000001b);		// bulk in ep no 1
	outpw(REG_USBD_EPA_START_ADDR, 0x00000100);
	outpw(REG_USBD_EPA_END_ADDR, 0x0000017f);

	/* bulk out */
	outpw(REG_USBD_EPB_IRQ_ENB, 0x00000010);	// data pkt received  and outtokenb
	outpw(REG_USBD_EPB_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPB_MPS, 0x00000040);		// mps 64
	outpw(REG_USBD_EPB_CFG, 0x00000023);		// bulk out ep no 2
	outpw(REG_USBD_EPB_START_ADDR, 0x00000200);
	outpw(REG_USBD_EPB_END_ADDR, 0x0000027f);
#endif
#ifdef USE_EPC_D
	/* bulk in */
	outpw(REG_USBD_EPC_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPC_MPS, 0x00000040);		// mps 64
	outpw(REG_USBD_EPC_CFG, 0x0000001b);		// bulk in ep no 1
	outpw(REG_USBD_EPC_START_ADDR, 0x00000100);
	outpw(REG_USBD_EPC_END_ADDR, 0x0000017f);

	/* bulk out */
	outpw(REG_USBD_EPD_IRQ_ENB, 0x00000010);	// data pkt received  and outtokenb
	outpw(REG_USBD_EPD_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPD_MPS, 0x00000040);		// mps 64
	outpw(REG_USBD_EPD_CFG, 0x00000023);		// bulk out ep no 2
	outpw(REG_USBD_EPD_START_ADDR, 0x00000200);
	outpw(REG_USBD_EPD_END_ADDR, 0x0000027f);
#endif
#ifdef USE_EPE_F
	/* bulk in */
	outpw(REG_USBD_EPE_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPE_MPS, 0x00000040);		// mps 64
	outpw(REG_USBD_EPE_CFG, 0x0000001b);		// bulk in ep no 1
	outpw(REG_USBD_EPE_START_ADDR, 0x00000100);
	outpw(REG_USBD_EPE_END_ADDR, 0x0000017f);

	/* bulk out */
	outpw(REG_USBD_EPF_IRQ_ENB, 0x00000010);	// data pkt received  and outtokenb
	outpw(REG_USBD_EPF_RSP_SC, 0x00000000);		// auto validation
	outpw(REG_USBD_EPF_MPS, 0x00000040);		// mps 64
	outpw(REG_USBD_EPF_CFG, 0x00000023);		// bulk out ep no 2
	outpw(REG_USBD_EPF_START_ADDR, 0x00000200);
	outpw(REG_USBD_EPF_END_ADDR, 0x0000027f);
#endif
}

void USB_Initialize()
{
	/* initial state */
	_usbd_devstate = 0;		//initial state
	_usbd_address  = 0;		//not set 
	_usbd_confsel  = 0;		//not selected
	_usbd_altsel   = 0;
	_usbd_speedset = 2;		// default at high speed mode

	/* 
	 * configure mass storage interface endpoint 
	 */
	
		usbdHighSpeedInit();
	

	/*
	 * configure USB controller 
	 */
#ifdef USE_EPA_B
	outpw(REG_USBD_IRQ_ENB_L, 0x0F);	/* enable usb, cep, epa, epb interrupt */
#endif
#ifdef USE_EPC_D
	outpw(REG_USBD_IRQ_ENB_L, 0x33);	/* enable usb, cep, epC, epD interrupt */
#endif
#ifdef USE_EPE_F
	outpw(REG_USBD_IRQ_ENB_L, 0xC3);	/* enable usb, cep, epE, epF interrupt */
#endif
	outpw(REG_USBD_IRQ_ENB, (USB_DMA_REQ | USB_RESUME | USB_RST_STS));
	outpw(REG_USBD_OPER, USB_HS);
	outpw(REG_USBD_ADDR, 0);

	/* allocate 0xff bytes mem for cep */
	outpw(REG_USBD_CEP_START_ADDR, 0);
	outpw(REG_USBD_CEP_END_ADDR, 0x07f);
	outpw(REG_USBD_CEP_IRQ_ENB, (CEP_SUPPKT | CEP_STS_END));

	//outpw(0xb000615c, 0xa);
}


extern INT  MASS_IO_Init(void);


INT main()
{
#if 1
	WB_PLL_T sysClock;

	sysClock.pll0 = PLL_200MHZ;
	sysClock.pll1 = PLL_200MHZ;
	sysClock.cpu_src = CPU_FROM_PLL0;
	sysClock.ahb_clk = AHB_CPUCLK_1_2;
	sysClock.apb_clk = APB_AHB_1_2;
	sysSetPLLConfig(&sysClock);
#endif

#ifdef CACHE_ON
	sysDisableCache();
	sysInvalidCache();
	sysEnableCache(CACHE_WRITE_BACK);
#endif

	outpw(REG_CLKEN, inpw(REG_CLKEN) | 0x100);
	outpw(REG_USBD_PHY_CTL, inpw(REG_USBD_PHY_CTL) | 0x300);

	/* wait PHY clock ready */
	while(1)
	{
		outpw(REG_USBD_EPA_MPS, 0x20);
		if (inpw(REG_USBD_EPA_MPS) == 0x20)
			break;
	}

    /* enable all mask interrupt */
    sysSetGlobalInterrupt(DISABLE_ALL_INTERRUPTS);

	/* set interrupt trigger type */
	//sysSetInterruptType(IRQ_USBD, LOW_LEVEL_SENSITIVE);

	/* Install ISR */
	sysInstallISR(IRQ_LEVEL_1, IRQ_USBD, (PVOID)usb_isr);

	sysSetTimerReferenceClock (TIMER0, 15000000);
	sysStartTimer (TIMER0, 100, PERIODIC_MODE);

    /* enable CPSR I bit */
    sysSetLocalInterrupt(ENABLE_IRQ);

	USB_Initialize();
	
	// set FMI reference clock
	sicIoctl(SIC_SET_CLOCK, 200000, 0, 0);
    Flash_Init();

	/* pull up the D+ */
	outpw(REG_PWRON, inpw(REG_PWRON) | 0x400);

	sysEnableInterrupt(IRQ_USBD);

#ifdef MIO_CACHE
	MASS_IO_Init();
#endif
	
	while (1)
	{
		if (USBModeFlag)
			MassBulk();
	}
}


extern unsigned int Image$$ZI$$Limit;

__value_in_regs struct R0_R3 {unsigned heap_base, stack_base, heap_limit, stack_limit;} 
    __user_initial_stackheap(unsigned int R0, unsigned int SP, unsigned int R2, unsigned int SL)
{
    struct R0_R3 config;

    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
    config.stack_base = sysGetSdramSizebyMB()*0x100000; //Stack base;

/*
To place heap_base directly above the ZI area, use:
    extern unsigned int Image$$ZI$$Limit;
    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
(or &Image$$region_name$$ZI$$Limit for scatterloaded images)

To specify the limits for the heap & stack, use e.g:
    config.heap_limit = SL;
    config.stack_limit = SL;
*/

    return config;
}

